package com.jwater.core.metrics.system;

import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.util.*;

import jwater.org.springframework.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jwater.core.utils.ProcessUtils;
import com.jwater.core.utils.SysType;

/**
 * @description:
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class NetMetric {
    protected static Logger logger = LoggerFactory.getLogger(NetMetric.class);

    public static Map<String, Set<Integer>> getUsedPort() {
        String sysType = SysType.getSysType();
        if (SysType.WINDOWS.equals(sysType)) {
            return getUsedPortForWin();
        } else if (SysType.LINUX.equals(sysType)) {
            return getUsedPortForLinux();
        }
        return new HashMap<String, Set<Integer>>();
    }

    private static Map<String, Set<Integer>> getUsedPortForWin() {
        Map<String, Set<Integer>> map = new HashMap<String, Set<Integer>>();
        Set<Integer> tcpPorts = new HashSet<Integer>();
        Set<Integer> udpPorts = new HashSet<Integer>();
        map.put("tcp", tcpPorts);
        map.put("udp", udpPorts);
        try {
            List<String> lines = ProcessUtils.cmd(null, "cmd /c netstat  -ano");
            for (String line : lines) {
                line = line.trim();
                if (line.startsWith("TCP") || line.startsWith("UDP")) {
                    String[] items = line.split("\\s+");
                    int index = items[1].lastIndexOf(":");
                    int port = Integer.parseInt(items[1].substring(index + 1));
                    if ("TCP".equals(items[0])) {
                        tcpPorts.add(port);
                    } else if ("UDP".equals(items[0])) {
                        udpPorts.add(port);
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
        return map;
    }

    private static Map<String, Set<Integer>> getUsedPortForLinux() {
        // 还可以根据/proc/net/tcp、/proc/net/tcp6、/proc/net/udp、/proc/net/udp6进行统计
        Map<String, Set<Integer>> map = new HashMap<String, Set<Integer>>();
        Set<Integer> tcpPorts = new HashSet<Integer>();
        Set<Integer> udpPorts = new HashSet<Integer>();
        map.put("tcp", tcpPorts);
        map.put("udp", udpPorts);
        try {
            List<String> lines = ProcessUtils.cmd(null, "netstat -lntu");
            for (String line : lines) {
                line = line.trim();
                if (line.startsWith("tcp") || line.startsWith("udp")) {
                    String[] items = line.split("\\s+");
                    int index = items[3].lastIndexOf(":");
                    int port = Integer.parseInt(items[3].substring(index + 1));
                    if (line.startsWith("tcp")) {
                        tcpPorts.add(port);
                    } else if (line.startsWith("udp")) {
                        udpPorts.add(port);
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
        return map;
    }

    public static Map<String, String> getHosts() {
        Map<String, String> hosts = new HashMap<String, String>();
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface inter = interfaces.nextElement();
                List<InterfaceAddress> addresses = inter.getInterfaceAddresses();
                if (!addresses.isEmpty()) {
                    for (InterfaceAddress address : addresses) {
                        String host = address.getAddress().getHostAddress();
                        if (host.split("\\.").length == 4) {
                            hosts.put(inter.getName(), host);
                            if ("127.0.0.1".equals(host)) {
                                hosts.put("local_hostname", "localhost");
                            } else {
                                hosts.put("hostname", address.getAddress().getHostName());
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
        return hosts;
    }

    public static Map<String, String> getNetRate() {
        String sysType = SysType.getSysType();
        if (SysType.WINDOWS.equals(sysType)) {
            return getNetRateForWin();
        } else if (SysType.LINUX.equals(sysType)) {
            return getNetRateForLinux();
        }
        return new HashMap<String, String>();
    }

    private static Map<String, String> getNetRateForWin() {
        Map<String, String> rates = new HashMap<String, String>();
        try {
            String procCmd = System.getenv("windir") + "//system32//wbem//wmic.exe "
                    + "path Win32_PerfFormattedData_Tcpip_NetworkInterface get BytesReceivedPersec,BytesSentPersec,Name /value";
            List<String> result = ProcessUtils.cmd(null, procCmd);
            int i = 0;
            String received = "";
            String sent = "";
            String name = "";
            for (String msg : result) {
                msg = msg.trim();
                if (StringUtils.isEmpty(msg)) {
                    continue;
                }
                i++;
                String[] items = msg.split("=");
                if ("BytesReceivedPersec".equals(items[0])) {
                    received = items[1];
                } else if ("BytesSentPersec".equals(items[0])) {
                    sent = items[1];
                } else if ("Name".equals(items[0])) {
                    name = items[1];
                }
                if (i % 3 == 0) {
                    rates.put(name, Integer.parseInt(received) * 1.0 / 8 + "K," + Integer.parseInt(sent) * 1.0 / 8 + "K");
                }
            }
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
        return rates;
    }

    private static Map<String, String> getNetRateForLinux() {
        // 还可以根据/proc/net/dev进行统计计算
        Map<String, String> rates = new HashMap<String, String>();
        try {
            List<String> lines = ProcessUtils.cmd(null, "ifstat");
            int i = 0;
            for (String line : lines) {
                line = line.trim();
                String[] items = line.split("\\s+");
                if (items.length >= 9) {
                    if (i > 0) {
                        rates.put(items[0], items[1] + "," + items[3]);
                    }
                    i++;
                }
            }
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
        return rates;
    }
}
